﻿//Srinivasan

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Tzync
{
    public class TreeOperation
    {
        private List<TreeNode> arrNode;
        private bool secondTime;
        private SystemType systemName;

        public TreeOperation(List<TreeNode> A, bool sT, SystemType st)
        {
            arrNode = A;
            secondTime = sT;
            systemName = st;
        }

        //Description     : For TreeNode N, this function gets the list of folder children from a list of all children.
        //Pre-Conditions  : TreeNode N is a directory node
        //Post-Conditions : A list of folder children is compiled and returned in alphabetical order.

        public List<int> getFolderChilds(TreeNode N)
        {            
            List<int> childs = N.GetChilds();
            List<int> folChilds = new List<int>();

            for (int i = 0; i < childs.Count()-1; i++)
            {                
                if (arrNode[childs[i]].GetNodeType().CompareTo(Type.Folder) == 0) 
                    folChilds.Add(childs[i]);
            }

            return folChilds;
        }

        //Description     : For TreeNode N, this function gets the list of file children from a list of all children.
        //Pre-Conditions  : TreeNode N is a directory node
        //Post-Conditions : A list of file children is compiled and returned in alphabetical order.

        public List<int> getFileChilds(TreeNode N)
        {            
            List<int> childs = N.GetChilds();
            List<int> FileChilds = new List<int>();

            for (int i = 0; i < childs.Count()-1; i++)
            {                
                if (arrNode[childs[i]].GetNodeType().CompareTo(Type.File) == 0) 
                    FileChilds.Add(childs[i]);
            }

            return FileChilds;
        }

        //Description     : System A (or Host) specific function. Given a root Directory and corresponding log entry 
        // TreeNode, this function simply computes the differences between them and adds to the
        // main list of differences.
        //Pre-Conditions  : D, N are not NULL.
        //Post-Conditions : The list of differences maintained in this class is updated, if necessary.

        public TreeNode UpdateRootNode(DirectoryInfo D, TreeNode N)
        {
            String dT = Utility.ParseDateTime(D.LastWriteTime);
            Pair<DirectionType, OperationType> f = new Pair<DirectionType, OperationType>();

            if (systemName == SystemType.Host)
            {
                N.SetFullPathHost(D.FullName);
                N.GetVersionHost().First = 1;
                N.GetVersionHost().Second = 0;
            }

            else
            {
                N.SetFullPathGuest(D.FullName);
                N.GetVersionHost().First = 1;
                N.GetVersionHost().Second = 0;
            }
            return N;         
        }        

        //Description     : In cases of creation in either systems, there doesnt exist an entry in metaData and in the 
        // tree of TreeNodes built from it. Hence, this function inserts a TreeNode in the appropriate
        // position in the tree for a file.
        //Pre-Conditions  : f is not NULL and parent are propoer values.
        //Post-Conditions : A TreeNode is CREATED FOR THE FILE and inserted in the tree arrNode.

        public TreeNode fileUpdateArrNode(FileInfo f, int parent)
        {
            if (f == null) throw new ArgumentNullException(f.FullName, ActionType.Analyze);
            if (parent < 0 || parent > arrNode.Count()) throw new ArgumentOutOfRangeException(ActionType.Analyze); 

            String DString;
            DString = (arrNode.Count()).ToString() + "|"; ;
            
            if (systemName.CompareTo(SystemType.Host) == 0) DString = DString + f.FullName + "|" + "|";
            else DString = DString + "|" + f.FullName + "|";

            if (systemName.CompareTo(SystemType.Host) == 0)
                DString = DString + "1,0" + "|" + f.Length.ToString() + "|" + "0,0" + "|" + "0";
            else DString = DString + "0,0" + "|" + "0" + "|" + "0,1" + "|" + f.Length.ToString();
            DString = DString + "|" + Utility.ParseDateTime(f.LastWriteTime) + "|" + Utility.ParseDateTime(f.LastWriteTime) + "|";
            DString = DString + parent.ToString() + "|";
            TreeNode n1 = new TreeNode(DString);
            arrNode.Add(n1);

            int k;            
            k = findSortIndex(parent, n1);                        
            arrNode[parent].PushChild(n1.GetId(), k);   //adding the file as a child to the parent
            return n1;
        }

        //Description     : In cases of creation in either systems, there doesnt exist an entry in metaData and in the 
        // tree of TreeNodes built from it. Hence, this function inserts a TreeNode in the appropriate
        // position in the tree for a DIRECTORY.
        //Pre-Conditions  : f is not NULL and direction and parent are propoer values.
        //Post-Conditions : A TreeNode is CREATED FOR THE DIRECTORY and inserted in the tree arrNode.

        public TreeNode folderUpdateArrNode(DirectoryInfo d, int parent)
        {
            if (d == null) throw new ArgumentNullException(d.FullName, ActionType.Analyze);
            if (parent < 0 || parent > arrNode.Count()) throw new ArgumentOutOfRangeException(ActionType.Analyze); 

            long size = Utility.CalculateDirectorySize(d);
            String DString = (arrNode.Count()).ToString() + "|";                        
            
            if (systemName.CompareTo(SystemType.Host) == 0) DString = DString + d.FullName + "|" + "|";
            else DString = DString + "|" + d.FullName + "|";

            if (systemName.CompareTo(SystemType.Host) == 0)
                DString = DString + "1,0" + "|" + size.ToString() + "|" + "0,0" + "|" + "0";
            else DString = DString + "0,0" + "|" + "0" + "|" + "0,1" + "|" + size.ToString();
            DString = DString + "|" + Utility.ParseDateTime(d.LastWriteTime) + "|" + Utility.ParseDateTime(d.LastWriteTime) + "|" + parent.ToString() + "|" + "-1";
            TreeNode n1 = new TreeNode(DString);
            arrNode.Add(n1);

            int k = findSortIndex(parent, n1);
            arrNode[parent].PushChild(n1.GetId(), k);   //adding the file as a child to the parent
            return n1;
        }

        //Description     : This function is used to find the index of a new Child to be inserted in lexicographic 
        // order in the list of all children of its parent.
        //Pre-Conditions  : n1 is not NULL and parent value is correct.
        //Post-Conditions : Index to be inserted according to lexicographic order is computed.

        private int findSortIndex(int parent, TreeNode n1)
        {                        
            int k;
            List<int> children = arrNode[parent].GetChilds();
            for (k = 0; k < children.Count() && children[k] != -1; k++)
                if (arrNode[children[k]].GetName().CompareTo(n1.GetName()) > 0)
                    break;
            return k;
        }        
    }
}
